#include "FSM.h"

FSM::FSM(string state, function<void()> onEnter) {
    _currState = state;
    _prevState = "";
    this->addState(state, onEnter);
}

FSM* FSM::create(string state, function<void()> onEnter) {
    FSM* fsm = new FSM(state, onEnter);
    if(fsm && fsm->init()) {
        fsm->autorelease();
        return fsm;
    }
    else {
        CC_SAFE_DELETE(fsm);
        return nullptr;
    }
}

FSM* FSM::addState(string state, function<void()> onEnter) {
    if("" == state) {
        log("FSM::addState: state can't be empty string!");
        return nullptr;
    }
    _states.insert(state);
    _onEnters.insert(pair<string, function<void()>>(state, onEnter));
    return this;
}

bool FSM::containState(string stateName) {
    return _states.find(stateName) != _states.end();
}

void FSM::printState() {
    //	for_each(_states.begin(), _states.end(), &FSM::print);
    log("FSM::printState: list of states");
    for(auto iter = _states.begin(); iter != _states.end(); iter++) {
        log(iter->c_str());
    }
}

void FSM::changeToState(string state) {
    if(containState(state)) {
        _prevState = _currState;
        _currState = state;
        log("FSM::changeToState: %s -> %s", _prevState.c_str(), _currState.c_str());
        if(_onEnters[state])
            _onEnters[state]();
    }
    else {
        log("FSM::changeToState: no such state as %s , state unchanged", state.c_str());
    }
}

FSM* FSM::addEvent(string eventName, string from, string to) {
    if("" == eventName) {
        log("FSM::addEvent: eventName can't be empty!");
        return nullptr;
    }
    if(!containState(from)) {
        log("FSM::addEvent: from state %s does not exit", from.c_str());
        return nullptr;
    }
    if(!containState(to)) {
        log("FSM::addEvent: to state %s does not exit", to.c_str());
        return nullptr;
    }
    unordered_map<string, string>& oneEvent = _events[eventName];
    oneEvent[from] = to;
    return this;
}

bool FSM::canDoEvent(string eventName) {
    return _events[eventName].find(_currState) != _events[eventName].end();
}

void FSM::doEvent(string eventName) {
    if(canDoEvent(eventName)) {
        log("FSM::doEvent: doing event %s", eventName.c_str());
        changeToState(_events[eventName][_currState]);
    }
    else {
        log("FSM::doEvent: cannot do event %s", eventName.c_str());
    }
}

void FSM::setOnEnter(string state, function<void()> onEnter) {
    if(containState(state)) {
        _onEnters[state] = onEnter;
    }
    else {
        log("FSM::setOnEnter: no state named %s", state.c_str());
    }
}

bool FSM::init() {
    
    return true;
}